package uk.ac.strath.cis.metric_spaces.distance;

import java.util.List;
import java.util.ListIterator;

import uk.ac.strath.cis.collections.ITree;
import uk.ac.strath.cis.metric_spaces.framework.FingerPrintProcessor;
import uk.ac.strath.cis.metric_spaces.util.Resolver;

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

public class StructuralEntropicTreeProcessor<E extends ITree<E>>
        implements FingerPrintProcessor<E, Multiset<Integer>> {

    private Multiset<Integer> fp;
    private Multiset<Integer> fingerPrint;

    public void process(E e) {
        fingerPrint = process(e, 0);
    }

    private Multiset<Integer> process(E e, int depth) {
    	if (e == null) throw new NullPointerException("Can't process null");
        Multiset<Integer> paths = HashMultiset.<Integer> create();
        if (depth == 0) {
            fp = paths;
        }
        paths.add(newPath(e));

        List<E> children = e.getChildren();
        for (ListIterator<E> iter = children.listIterator(children.size()); iter
                .hasPrevious();) {
            Multiset<Integer> childpaths = process(iter.previous(), depth + 1);
            for (int path : childpaths) {
                paths.add(newPath(e, path));
            }
        }

        if (depth > 0) {
            fp.addAll(paths);
        }

        return paths;
    }

    private int newPath(E e) {
        return Resolver.instance.lookup(e.getNodeName());
    }

    private int newPath(E e, int child) {
        return Resolver.instance.lookup(e.getNodeName() + "/" + Resolver.instance.lookup(child));
    }

    public Multiset<Integer> getFingerPrint() {
        return fingerPrint;
    }
}
